﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Civilisation_code.PPartie;
using Civilisation_code.PInterfaces_Fabrique_Unite;
using Civilisation_code.PCarte;
using Civilisation_code.PJoueur;
using Civilisation_code.PRessource;
using Civilisation_code.PVCarte;
using Civilisation_code.Implementation_Unite_INFO;
using System.Threading.Tasks;
using WPF_Civilisation;
using System.ComponentModel;
using System.Threading;

namespace WPF_Civilisation
{
    /// <summary>
    /// Logique d'interaction pour Window_Carte.xaml
    /// </summary>
    public partial class Window_Carte : Window
    {
        /// <summary>
        /// Lien avec le modèle, partie en cours
        /// </summary>
        private Partie _partie;

        /// <summary>
        /// Associe une unité au rectangle lui correspondant
        /// </summary>
        private Hashtable _unites;

        /// <summary>
        /// Liste des unités sélectionnées par l'utilisateur dans l'onglet Unité
        /// Permet d'effectuer des déplacements successifs
        /// </summary>
        private List<Unite> _unites_selectionnees;

        /// <summary>
        /// Booléane permettant de savoir si c'est une nouvelle partie ou une partie ancienne chargée
        /// </summary>
        private bool _charger_partie = false;

        /// <summary>
        /// Associe à une case, le rectangle et l'ellipse (contenant le nombre d'unités) lui correspondant
        /// </summary>
        public Hashtable _cases { get; set; }

        /// <summary>
        /// Garde en mémoire la dernière case sélectionnée par un joueur que ce dernier ne soit pas perdu lorsque c'est à son tour de jouer
        /// </summary>
        public Hashtable _derniere_case_selectionne;



        /// <summary>
        /// Constructeur de la fenêtre avec en paramètres les configurations souhaitées par l'utilisateur
        /// Création d'une nouvelle partie
        /// </summary>
        /// <param name="joueurs">Informations sur les joueurs (pseudo + civilisation + couleur)</param>
        /// <param name="grande">Si la taille demandée de la map est "normale"</param>
        /// <param name="w">Fenêtre de configuration de la partie qui a appelée la création de la fenêtre</param>
        public Window_Carte(Hashtable joueurs,bool grande,Window_Configuration w)
        {
            InitializeComponent();

            //Instantiation des variables
            _unites = new Hashtable();
            _cases = new Hashtable();
            _unites_selectionnees = new List<Unite>();
            _derniere_case_selectionne = new Hashtable();

            //Création de la partie
            Createur_Partie createur = new Createur_Partie();
            createur.construirePartie(joueurs, grande);
            _partie = createur._monteur._partie;

            //Mise à jour de l'évolution de la création de cette fenêtre dans la fenêtre de configuration
            w.updateProgressBar(50);
            
            //Affichage
            affichageMap(w);
            updateInfoJoueurs();

            //Début de la partie
            gestionDebutPartie();
        }

        /// <summary>
        /// Constructeur de la fenêtre avec en paramètre le chemin du fichier de sauvegarde d'une partie antérieure
        /// </summary>
        /// <param name="path">Chemin du fichier de sauvegarde</param>
        public Window_Carte(String path)
        {
            InitializeComponent();

            //Instantiation
            _unites = new Hashtable();
            _cases = new Hashtable();
            _derniere_case_selectionne = new Hashtable();
            _unites_selectionnees = new List<Unite>();

            //Chargement de la Partie
            _partie = Partie.charger(path);
            _charger_partie = true;

            //Affichage
            affichageMap(null);
            updateInfoJoueurs();

            gestionDebutPartie();
        }

        /// <summary>
        /// Méthode permettant de sélectionner la case et focaliser la vue sur celle-ci
        /// </summary>
        private void gestionDebutPartie()
        {
            //Ajout un observateur sur la partie
            _partie.PropertyChanged += new PropertyChangedEventHandler(changement_partie);

            //Si c'est une nouvelle partie, alors on lance les tâches de début de partie
            if (_charger_partie == false)
                _partie.debut();
            //Sinon on met à jour les données graphiques concernant la partie (donc le nombre de tour...)
            else
            {
                _partie.NumJoueurActif = _partie.NumJoueurActif;
                _partie.getJoueurActif().vueSur();
                num_tour.Content = _partie.Nb_tour;
            }

            //On ajoute une limite de grandeur à grid affichant la carte
            mapGrid.MaxWidth = 50 * _partie._carte._largeur;

            //On centre la vue sur la dernière case que le joueur a selectionnée
            Rectangle rec = (Rectangle)_derniere_case_selectionne[_partie.getJoueurActif()];
            double offset_x = (Grid.GetColumn(rec)) * 50 + ((800 - 200) / 2) - (800 - 200);
            double offset_y = (Grid.GetRow(rec)) * 50 + ((800 - 200) / 2) - (800 - 200);
            scroll.ScrollToHorizontalOffset(offset_x);
            scroll.ScrollToVerticalOffset(offset_y);

            //On simule un clique sur cette case afin de mettre à jours les onglets et les informations
            clique_sur_une_case(rec, null);
        }
      
        /// <summary>
        /// Méthode de création des élements graphiques de la grid (carte)
        /// </summary>
        /// <param name="w">Fenêtre de configuration qui a lancée la création de la fenêtre. Ce paramètre va permettre de mettre à jour l'évolution de la création de la partie (affichage)</param>
        private void affichageMap(Window_Configuration w)
        {
           Carte map = _partie._carte;
           
           //Définition des colonnes de la grid
           for (int c = 0; c < map._largeur; c++)
           {
               mapGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(50, GridUnitType.Pixel) });

           }
           //Création des éléments de la grid
           for (int l = 0; l < map._hauteur; l++)
           {
               //On met à jour l'évolution de l'affichage
               if(w!=null)
                w.updateProgressBar(50 + (l * 50) / map._hauteur);

               mapGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(50, GridUnitType.Pixel) });
               
               for (int c = 0; c < map._largeur; c++)
               {
                   Rectangle r = null;
                   //On crée un rectangle pour case représentant les ressources
                   r = createCase(c, l, map.getCase(c, l));
                   mapGrid.Children.Add(r);
                   //On crée une ellipse donnant une information rapide sur le nombre de troupes situé sur la case
                   mapGrid.Children.Add(createEllipseUnite(c, l, r));

                   //On ajoute toutes unités sur la carte
                   foreach (Unite u in map.getCase(c, l).Unites)
                   {
                       mapGrid.Children.Add(affichageUnite(u, u.getType()));
                   }
               }
           }
       }

        /// <summary>
        /// Méthode appelée lorsqu'il y a du changement dans le modèle (classe Partie)
        /// </summary>
        /// <param name="sender">Partie</param>
        /// <param name="e">Evènement</param>
        private void changement_partie(object sender, PropertyChangedEventArgs e)
        {
            //Si c'est le joueur actif qui a été modifié
            if (e.PropertyName.Equals("joueur_actif"))
            {
                //On met à jour le tour du joueur sur la vue
                couleur_joueur_actif.Fill = _partie.getJoueurActif().Color;
                nom_joueur_actif.Content = _partie.getJoueurActif()._nom;
                return;
            }

            //Si c'est le numero de tour qui a été modifié
            if (e.PropertyName.Equals("nb_tour"))
            {
                //On met à jour le numéro de tour
                num_tour.Content = _partie.Nb_tour;
                return;
            }

            //Si la partie est terminée
            if (e.PropertyName.Equals("partie_terminee"))
            {
                afficher_partie_terminee();
                return;
            }

            //Sinon, un joueur est éliminé

            //On affiche un message à l'écran
            string messageBoxText = "Le joueur "+e.PropertyName+" est éliminé.";
            string caption = "Elimination d'un joueur";
            MessageBoxButton button = MessageBoxButton.OK;
            MessageBoxImage icon = MessageBoxImage.Information;
            System.Windows.MessageBox.Show(messageBoxText, caption, button, icon);

            //On raye son nom dans l'onglet à droite
            foreach (UIElement element in header_joueurs.Items)
            {
                StackPanel s = element as StackPanel;
                TextBlock l = (TextBlock)s.Children[1];
                if (l.Text.Equals(e.PropertyName))
                {
                    l.IsEnabled = false;
                    l.TextDecorations = TextDecorations.Strikethrough;
                }
            }
        }

        /// <summary>
        /// Méthode permettant l'affichage d'une fenêtre de dialogue indiquant la fin de la partie
        /// </summary>
        private void afficher_partie_terminee()
        {
            string messageBoxText = "Victoire du joueur "+_partie.getJoueurActif()._nom+" en "+_partie.Nb_tour+" tours.";
            string caption = "Partie terminée";
            MessageBoxButton button = MessageBoxButton.OK;
            MessageBoxImage icon = MessageBoxImage.Information;

            System.Windows.MessageBox.Show(messageBoxText, caption, button, icon);

            quitter(null,null);
        }

        /// <summary>
        /// Construction des informations des joueurs sur la partie droite de la fenêtre
        /// </summary>
        private void updateInfoJoueurs()
        {
            //Pour chaque joueur de la partie, on affiche un rectangle représentant sa couleur et son pseudo
            foreach (Joueur j in _partie._joueurs)
            {
                StackPanel tmp = new StackPanel();
                tmp.Orientation = Orientation.Horizontal;

                Rectangle rec = new Rectangle();
                rec.Width = 15;
                rec.Height = 10;
                rec.Fill = j.Color;
                tmp.Children.Add(rec);

                TextBlock lab = new TextBlock();
                lab.Padding = new Thickness(5,0,0,0);
                lab.FontWeight = FontWeights.Normal;
                lab.FontStyle = FontStyles.Italic;
                lab.Text = j._nom;
                tmp.Children.Add(lab);
                header_joueurs.Items.Add(tmp);
            }        
        }

        /// <summary>
        /// Création d'une ellipse indiquant le nombre de troupes sur une case
        /// </summary>
        /// <param name="c">Position sur l'axe des abscisses</param>
        /// <param name="l">Position sur l'axe des ordonnées</param>
        /// <param name="r">Rectangle de la case associé</param>
        /// <returns>L'ellipse nouvellement créée</returns>
        private Label createEllipseUnite(int c, int l, Rectangle r)
        {
            Label ellipse_unit = new Label();
            
            Case a = (Case)r.Tag;

            //On associe la case au rectangle et à l'ellipse
            _cases.Add(a, new Tuple<Rectangle, Label>(r, ellipse_unit));

            ellipse_unit.Tag = a;
            ellipse_unit.Content = a.Unites.Count;
            ellipse_unit.Height = 20;
            ellipse_unit.Width = 30;
            ellipse_unit.Margin = new Thickness(10, 20, 0, 0);
            ellipse_unit.Padding = new Thickness(6, 2, 0, 0);
            VisualBrush vbrush = new VisualBrush();
            Ellipse el = new Ellipse();
            el.Height = 10;
            el.Width = 10;
            vbrush.Visual = el;
            ellipse_unit.Background = vbrush;

            //Si il n'y a pas d'unités sur cette case, alors on n'affiche pas l'ellipse
            if (a.Unites.Count == 0)
                ellipse_unit.Visibility = Visibility.Hidden;
            //Sinon on l'affiche avec comme couleur de fond, celle du joueur
            else
            {
                el.Fill = a._joueur.Color;
                if (_derniere_case_selectionne.ContainsKey(a._joueur))
                    _derniere_case_selectionne[a._joueur]=r;
                else
                    _derniere_case_selectionne.Add(a._joueur,r);
            }

            if (a.Brouillard)
                ellipse_unit.Visibility = Visibility.Hidden;

            //Placement de l'ellipse sur la grid
            Grid.SetColumn(ellipse_unit, c);
            Grid.SetRow(ellipse_unit, l);

            return ellipse_unit;
        }

        /// <summary>
        /// Création du rectangle affichant une case notamment ses ressources
        /// </summary>
        /// <param name="c">Position sur l'axe des abscisses</param>
        /// <param name="l">Position sur l'axe des ordonnées</param>
        /// <param name="ca">Case</param>
        /// <returns>Rectangle créé</returns>
        private Rectangle createCase(int c, int l, Case ca)
        {
            //Création du rectangle
            Rectangle rectangle = new Rectangle();

            //Si il a le brouillard de guerre sur cette case
            if(ca.Brouillard)
                rectangle.Opacity = 0.5;

            Ville v = ca.Ville;

            //Si une ville est située sur la case
            if (v != null)
            {
                //On met en évidence la case par des bordures pleines et de la couleur du joueur
                v.PropertyChanged += new PropertyChangedEventHandler(changement_ville);
                rectangle.StrokeThickness = 8;
                rectangle.Stroke = v.Joueur.Color;

            }
            //Si la case a été annexée par une ville
            else if(ca.Ville_annexee != null){
                //On met en évidence la case par des bordures en pointillé et de la couleur du joueur

                DoubleCollection _dotted = new DoubleCollection();
                _dotted.Add(2);
                _dotted.Add(2);

                rectangle.StrokeDashArray = _dotted;
                rectangle.Stroke = ca.Ville_annexee.Joueur.Color;
                rectangle.StrokeThickness = 3;
            }
            else
            {
                rectangle.StrokeThickness = 3;
            }

            
            rectangle.Fill = selectionCaseImage(ca);
            rectangle.Tag = ca;
            //Le rectangle est un observateur de la case
            ca.PropertyChanged += new PropertyChangedEventHandler(changement_case);
            //Placement du rectangle à la bonne position
            Grid.SetColumn(rectangle, c);
            Grid.SetRow(rectangle, l);

            //Ajout d'un listener de clique gauche
            rectangle.MouseLeftButtonDown += new MouseButtonEventHandler(clique_sur_une_case);
            return rectangle;
        }

        /// <summary>
        /// Méthode appelée lorsqu'au niveau du modèle, une case a été modifiée
        /// </summary>
        /// <param name="sender">Case qui a générée l'appel</param>
        /// <param name="e">Evènement</param>
        private void changement_case(object sender, PropertyChangedEventArgs e)
        {
            //Case modifiée
            Case c = sender as Case;

            Tuple<Rectangle,Label> t = (Tuple<Rectangle,Label>)_cases[c];

            //Rectangle correspondant à la case
            Rectangle r = t.Item1;
            //Ellipse des unités correspondant à la case
            Label l = t.Item2;

            //Si l'évènement est du à un changement de visibilité de la case
            if (e.PropertyName.Equals("brouillard"))
            {
                //Si la case n'est pas brouillée
                if (!c.Brouillard)
                {
                    //On re tire le brouillard
                    r.Opacity = 1;

                    //On affiche l'ellipse si il y au moins une unité
                    if (l.Content.Equals(0))
                        l.Visibility = Visibility.Hidden;
                    else
                        l.Visibility = Visibility.Visible;

                    //On affiche les images de toutes les unités
                    foreach (Unite u in c.Unites)
                        ((Rectangle)_unites[u]).Visibility = Visibility.Visible;
                }
                //Sinon
                else
                {
                    //On brouille la case
                    r.Opacity = 0.5;

                    //On n'affiche pas l'ellipse
                    l.Visibility = Visibility.Hidden;

                    //On n'affiche pas l'image correspondant à chaque unité se trouvant sur la case
                    foreach (Unite u in c.Unites)
                        ((Rectangle)_unites[u]).Visibility = Visibility.Hidden;
                }
                return;
            }
            //Si la case a été annexée
            else if (e.PropertyName.Equals("ville_annexee"))
            {
                //On met en évidence la case par des bordures en pointillé et de la couleur du joueur

                DoubleCollection _dotted = new DoubleCollection();
                _dotted.Add(2);
                _dotted.Add(2);

                r.StrokeDashArray = _dotted;
                r.Stroke = c.Ville_annexee.Joueur.Color;
                r.StrokeThickness = 3;


                return;
            }
            //Si une ville s'est construite sur la case
            else if (e.PropertyName.Equals("ville"))
            {
                r.StrokeThickness = 6;
                r.Stroke = c.Ville.Joueur.Color;
               
                c.Ville.PropertyChanged += new PropertyChangedEventHandler(changement_ville);

               
                return;

            }
            //Si une unité a été produite sur cette case par une ville
            else if (e.PropertyName.Equals("ajout_unite"))
            {
                //On met à jour le nombre dans l'ellipse
                int cou = c.Unites.Count;
                t.Item2.Content = c.Unites.Count;

                //On affiche l'image correspondant à l'unité
                mapGrid.Children.Add(affichageUnite(c.Unites[cou - 1], c.Unites[cou - 1].getType()));

                return;
            }
            //Si une unité n'est plus sur cette case
            else if (e.PropertyName.Equals("enleve_unite"))
            {
                //On met à jour l'ellipse
                int cou = c.Unites.Count;
                l.Content = c.Unites.Count;
                if (l.Content.Equals(0))
                {
                    l.Visibility = Visibility.Hidden;
                }
                else
                {
                    l.Visibility = Visibility.Visible;
                }

            }
        }

        /// <summary>
        /// Méthode appelée lorsqu'au niveau du modèle, une ville a été modifiée
        /// </summary>
        /// <param name="sender">Ville qui a générée l'appel</param>
        /// <param name="e">Evènement</param>
        private void changement_ville(object sender, PropertyChangedEventArgs e)
        {
            //On récupère la ville qui a générée l'appel
            Ville v = sender as Ville;

            //Si la ville a été prisée
            if (e.PropertyName.Equals("prise"))
            {
                Tuple<Rectangle, Label> t = (Tuple<Rectangle, Label>)_cases[v.Case];

                //Rectangle correspondant à la case où est située la ville
                Rectangle r = t.Item1;
                //Mise à jour des couleurs de la bordure avec la couleur du joueur qui a prisé
                r.Stroke = v.Joueur.Color;

                //De même pour les cases annexées par cette ville
                foreach (Case ca in v._cases_annexes)
                {
                    Tuple<Rectangle, Label> t2 = (Tuple<Rectangle, Label>)_cases[ca];

                    //Rectangle correspondant à la case
                    Rectangle r2 = t2.Item1;
                    r2.Stroke = v.Joueur.Color;
                }                
            }

            if (e.PropertyName.Equals("changement_unite_a_produire"))
            {
                updateOnglets(v.Case);
            }
        }

        /// <summary>
        /// Méthode retournant l'imageBrush correspondant aux ressources de la case
        /// </summary>
        /// <param name="ca"></param>
        /// <returns></returns>
        private ImageBrush selectionCaseImage(Case ca)
        {
            ImageBrush im= new ImageBrush();
            if (ca._ressource.Equals(Fabrique_Ressource.FABRIQUE_RESSOURCE.obtenirRessource("Plaine", "")))
                return Fabrique_Img_Ressource.FABRIQUE_IMG_RESSOURCE.obtenirRessource("Plaine", "");
            else if (ca._ressource.Equals(Fabrique_Ressource.FABRIQUE_RESSOURCE.obtenirRessource("Plaine", "Fer")))
                return Fabrique_Img_Ressource.FABRIQUE_IMG_RESSOURCE.obtenirRessource("Plaine", "Fer");
            else if (ca._ressource.Equals(Fabrique_Ressource.FABRIQUE_RESSOURCE.obtenirRessource("Plaine", "Fruit")))
                return Fabrique_Img_Ressource.FABRIQUE_IMG_RESSOURCE.obtenirRessource("Plaine", "Fruit");
            else if (ca._ressource.Equals(Fabrique_Ressource.FABRIQUE_RESSOURCE.obtenirRessource("Desert", "")))
                return Fabrique_Img_Ressource.FABRIQUE_IMG_RESSOURCE.obtenirRessource("Desert", "");
            else if (ca._ressource.Equals(Fabrique_Ressource.FABRIQUE_RESSOURCE.obtenirRessource("Desert", "Fer")))
                return Fabrique_Img_Ressource.FABRIQUE_IMG_RESSOURCE.obtenirRessource("Desert", "Fer");
            else if (ca._ressource.Equals(Fabrique_Ressource.FABRIQUE_RESSOURCE.obtenirRessource("Desert", "Fruit")))
                return Fabrique_Img_Ressource.FABRIQUE_IMG_RESSOURCE.obtenirRessource("Desert", "Fruit");
            else if (ca._ressource.Equals(Fabrique_Ressource.FABRIQUE_RESSOURCE.obtenirRessource("Montagne", "")))
                return Fabrique_Img_Ressource.FABRIQUE_IMG_RESSOURCE.obtenirRessource("Montagne", "");
            else if (ca._ressource.Equals(Fabrique_Ressource.FABRIQUE_RESSOURCE.obtenirRessource("Montagne", "Fer")))
                return Fabrique_Img_Ressource.FABRIQUE_IMG_RESSOURCE.obtenirRessource("Montagne", "Fer");
            else if (ca._ressource.Equals(Fabrique_Ressource.FABRIQUE_RESSOURCE.obtenirRessource("Montagne", "Fruit")))
                return Fabrique_Img_Ressource.FABRIQUE_IMG_RESSOURCE.obtenirRessource("Montagne", "Fruit");

            return null;
        }

        /// <summary>
        /// Méthode permettant la mise à jour des informations dans le panel de droite
        /// </summary>
        /// <param name="c">Case selectionnée</param>
        private void updateInfos(Case c)
        {
            UIElementCollection u = stack_case.Children;
            if (u.Count > 1)
                u.RemoveAt(u.Count - 1);

            //Si la case sélectionnée est une case annexee
            if (c.Ville_annexee != null)
            {
                StackPanel tmp = new StackPanel();
                tmp.Orientation = Orientation.Horizontal;

                Label la = new Label();
                la.Content = "Annexée par";
                la.FontWeight = FontWeights.Normal;

                Label la1 = new Label();
                la1.Content = c.Ville_annexee.Case._x;
                la1.Padding = new Thickness(0, 5, 0, 5);
                la1.FontStyle = FontStyles.Italic;
                la1.FontWeight = FontWeights.Normal;

                Label la2 = new Label();
                la2.Padding = new Thickness(0, 5, 0, 5);
                la2.Content = ":";
                la2.FontStyle = FontStyles.Italic;
                la2.FontWeight = FontWeights.Normal;

                Label la3 = new Label();
                la3.Padding = new Thickness(0, 5, 0, 5);
                la3.Content = c.Ville_annexee.Case._y;
                la3.FontStyle = FontStyles.Italic;
                la3.FontWeight = FontWeights.Normal;

                tmp.Children.Add(la);
                tmp.Children.Add(la1);
                tmp.Children.Add(la2);
                tmp.Children.Add(la3);
                stack_case.Children.Add(tmp);
            }
           
            //Si il y a une ville sur cette case, on met à jour les infos
            if (c.Ville != null)
            {
                ville_joueur.Content = c.Ville.Joueur._nom;
                ville_fruit.Content = c.Ville.productionFruit();
                ville_minerais.Content = c.Ville.productionMinerais();
                ville_population.Content = c.Ville._population;

                ongletVilleU.onglet_ville_minerais.Content = ville_minerais.Content;
                ongletVilleU.onglet_ville_fruit.Content = ville_fruit.Content;

                ongletVilleU.onglet_ville_minerais_stock.Content = c.Ville._minerai;
                ongletVilleU.onglet_ville_fruit_stock.Content = c.Ville._nourriture;

                header_ville.IsEnabled = true;

            }
            //Sinon on rend indisponible les informations
            else
                header_ville.IsEnabled = false;


            //Si la case est brouillée, on ne met aucune information sur les unités
            if(c.Brouillard)
            {
                nbre_etudiant_case.Content = 0;
                nbre_directeur_case.Content = 0;

                nbre_enseignant_case.Content = 0;
                header_unites_presentes.IsEnabled = false;
                nom_joueur_unites.Content = "Aucun";
            }
            //Sinon si....
            else
            {
                nbre_etudiant_case.Content = c.getNombreTypeUnite("Etudiant");
                nbre_directeur_case.Content = c.getNombreTypeUnite("Directeur");
                nbre_enseignant_case.Content = c.getNombreTypeUnite("Enseignant");

                if (!nbre_etudiant_case.Content.Equals(0) || !nbre_directeur_case.Content.Equals(0) || !nbre_enseignant_case.Content.Equals(0))
                {
                    header_unites_presentes.IsEnabled = true;
                    nom_joueur_unites.Content = c._joueur._nom;
                }
                else
                {
                    header_unites_presentes.IsEnabled = false;
                    nom_joueur_unites.Content = "Aucun";
                }
            }
        }

        /// <summary>
        /// Méthode appelée lors d'un clic sur une case
        /// Met en valeur la case cliquée
        /// </summary>
        /// <param name="sender">Rectangle (Case) cliqué</param>
        /// <param name="e">Evènement</param>
        public void clique_sur_une_case(object sender, MouseButtonEventArgs e)
        {
            //On récupère le rectangle cliqué
            var rectangle = sender as Rectangle;

            _derniere_case_selectionne[_partie.getJoueurActif()] = rectangle;

            //On récupère la case associée
            var tile = rectangle.Tag as Case;
           
            int column = Grid.GetColumn(rectangle);
            int row = Grid.GetRow(rectangle);

            //On place le rectangle de selection sur la case sélectionnée
            Grid.SetColumn(selectionCase, column);
            Grid.SetRow(selectionCase, row);

            selectionCase.Tag = tile;
            selectionCase.Visibility = System.Windows.Visibility.Visible;

            //Update des informations à droite
            treeview.IsEnabled = true;

            //On met à jour les informations sur le panel droit et dans les onglets
            updateInfos(tile);
            updateOnglets(tile);
            
        }

        /// <summary>
        /// Méthode permettant d'afficher une unité
        /// </summary>
        /// <param name="u">Unité à afficher</param>
        /// <param name="type">Le type de l'unité</param>
        /// <returns>Rectangle représentant l'unité nouvellement créée</returns>
        private Rectangle affichageUnite(Unite u, string type)
        {

            Rectangle r = new Rectangle();
            _unites.Add(u,r);

            //Récupération de l'image correspondant au type de l'unité et de la civilisation du joueur
            r.Fill = Fabrique_Img_Unite.FABRIQUE_IMG_UNITE.obtenirUnite(u._joueur._civilisation, type);

            if (type.Equals("Directeur"))
                r.Margin = new Thickness(-20, -10, 0, 0);
            if (type.Equals("Etudiant"))
                r.Margin = new Thickness(0, -10, 0, 0);
            if (type.Equals("Enseignant"))
                r.Margin = new Thickness(20, -10, 0, 0);

            r.Width = 18;
            r.Height = 18;
             
            r.Tag = u;

            if (u.Case.Brouillard)
                r.Visibility = Visibility.Hidden;

            //Ajout d'un observateur sur cette unité
            u.PropertyChanged += new PropertyChangedEventHandler(changement_unite);

            //Unité toujours visible (premier plan)
            Panel.SetZIndex(r,999);
            Grid.SetColumn(r, u.Case._x);
            Grid.SetRow(r, u.Case._y);

            return r;
        }


        /// <summary>
        /// Méthode appelée lorsqu'une instance d'Unité à été modifiée
        /// </summary>
        /// <param name="sender">Unité modifiée</param>
        /// <param name="e">Evènement</param>       
        private void changement_unite(object sender, PropertyChangedEventArgs e)
        {
            //Récupération de l'unité et du rectangle qui lui est associé
            Unite u = sender as Unite;
            Rectangle r = (Rectangle) _unites[u];
            Tuple<Rectangle, Label> t = (Tuple<Rectangle, Label>)_cases[u.Case];

            //Si l'évènement est du à l'unité qui a bougé
            if (e.PropertyName.Equals("unite_bouge"))
            {
                //On met à jour l'ellipse (couleur + contenu)
                t.Item2.Content = u.Case.Unites.Count;
                ((Ellipse)((VisualBrush)t.Item2.Background).Visual).Fill = u._joueur.Color;
                t.Item2.Visibility = Visibility.Visible;

                //On met l'affichage de l'unité sur la nouvelle case
                Grid.SetColumn(r, u.Case._x);
                Grid.SetRow(r, u.Case._y);
                return;
            }
            //Si c'est du à la mort de l'unité
            else if (e.PropertyName.Equals("unite_morte"))
            {
                //On met à jour l'ellipse
                t.Item2.Content = u.Case.Unites.Count;
                if (t.Item2.Content.Equals(0))
                {
                    t.Item2.Visibility = Visibility.Hidden;
                }
                else
                {
                    t.Item2.Visibility = Visibility.Visible;
                }

                _unites.Remove(u);
                //On retire l'image de la grid
                mapGrid.Children.Remove(r);

                //On réactualise le brouillard
                _partie.getJoueurActif().vueSur();

                Case ca = (Case)selectionCase.Tag;
                Tuple<Rectangle, Label> ta = (Tuple<Rectangle, Label>)_cases[ca];

                //Rectangle correspondant à la case
                Rectangle ra = t.Item1;

                clique_sur_une_case(ra, null);

            }

        }

        /// <summary>
        /// Méthode de mise à jour des onglets
        /// </summary>
        /// <param name="c">Case sélectionnée</param>
        private void updateOnglets(Case c)
        {
            updateOngletUnite(c);
            updateOngletVille(c);
        }

        /// <summary>
        /// Méthode de mise à jour du contenu de l'onglet Unité
        /// </summary>
        /// <param name="c">Case sélectionnée</param>
        private void updateOngletUnite(Case c)
        {
            UIElement element = ongletUniteU.gridUnite.Children[ongletUniteU.gridUnite.Children.Count - 1];
            if (element.GetType() == typeof(Button))
            {
                element.IsEnabled = false;
                element.Visibility = Visibility.Visible;
            }
            else
            {
                Button but = new Button();
                but.Content = "Tout sélectionner";
                but.Click += new RoutedEventHandler(tout_selectionner_unites);
                but.Width = 100;
                but.HorizontalAlignment = HorizontalAlignment.Left;
                Grid.SetColumn(but, 1);
                Grid.SetRow(but, 0);
                ongletUniteU.gridUnite.Children.Add(but);
            }

            bool unite_peut_bouger = false;
            //Si il n'y a pas d'unités sur la case ou que la case est non visible
            if (c.Unites.Count == 0 || c.Brouillard == true)
            {
                //On n'affiche rien sauf un message alertant l'utilisateur
                ongletUnite.IsEnabled = false;
                foreach (UIElement u in ongletUniteU.gridUnite.Children)
                {
                    u.Visibility = Visibility.Hidden;
                }
                element.IsEnabled = false;
                ongletUniteU.aucune_unite.Visibility = Visibility.Visible;
                return;
            }

            tab_control.SelectedItem = ongletUnite;

            //Sinon, on affiche tout
            ongletUnite.IsEnabled = true;

            if (c.Unites[0]._joueur != _partie.getJoueurActif())
            {
                ongletUniteU.listeDirecteur.IsEnabled = false;
                ongletUniteU.listeEnseignant.IsEnabled = false;
                ongletUniteU.listeEtudiant.IsEnabled = false;
                element.IsEnabled = false;
            }
            else
            {
                ongletUniteU.listeDirecteur.IsEnabled = true;
                ongletUniteU.listeEnseignant.IsEnabled = true;
                ongletUniteU.listeEtudiant.IsEnabled = true;
            }

            ongletUniteU.listeDirecteur.Children.Clear();
            ongletUniteU.listeEnseignant.Children.Clear();
            ongletUniteU.listeEtudiant.Children.Clear();

            ongletUniteU.la_directeur.Visibility = Visibility.Visible;
            ongletUniteU.la_enseignant.Visibility = Visibility.Visible;
            ongletUniteU.la_etudiant.Visibility = Visibility.Visible;

            ongletUniteU.listeDirecteur.Visibility = Visibility.Visible;
            ongletUniteU.listeEnseignant.Visibility = Visibility.Visible;
            ongletUniteU.listeEtudiant.Visibility = Visibility.Visible;

            ongletUniteU.aucune_unite.Visibility = Visibility.Hidden;



            //On parcourt la liste des unités de la classe, et on construit dynamiquement l'affichage
            foreach (Unite u in c.Unites)
            {
                //Si l'unité est un directeur
                if(u.GetType().IsSubclassOf(typeof(Directeur))){
                    StackPanel s = new StackPanel();
                    s.Orientation = Orientation.Horizontal;

                    Label l = new Label();
                    l.Width = 200;
                    l.Content = "Vie : " + u._vie_restante + " - Mouvement restant : " + u._mvt_restant;

                    CheckBox b = new CheckBox();
                    b.VerticalAlignment = VerticalAlignment.Center;

                    b.Tag = u;
                    if (u._mvt_restant == 0)
                        b.IsEnabled = false;
                    else
                    {
                        unite_peut_bouger = true;
                        if (_unites_selectionnees.Contains(u))
                            b.IsChecked = true;
                    }

                    s.Children.Add(b);
                    s.Children.Add(l);

                    ongletUniteU.listeDirecteur.Children.Add(s);
                }
                //Si l'unité est en enseignant
                else if (u.GetType().IsSubclassOf(typeof(Enseignant)))
                {
                    StackPanel s = new StackPanel();
                    s.Orientation = Orientation.Horizontal;

                    Label l = new Label();
                    l.Width = 200;
                    l.Content = "Vie : " + u._vie_restante + " - Mouvement restant : " + u._mvt_restant;

                    CheckBox b = new CheckBox();
                    b.VerticalAlignment = VerticalAlignment.Center;

                    b.Tag = u;

                    Button b2 = new Button();
                    b2.Content = "Fonder le village";
                    b2.Margin = new Thickness(0, 0, 10, 0);
                    b2.Tag = u;
                    //Ajout d'un écouteur sur le bouton
                    b2.Click += new RoutedEventHandler(fonder_village);

                    Button b3 = new Button();
                    b3.Content = "Aide pour fonder un village";
                    b3.Tag = u;
                    //Ajout d'un écouteur sur le bouton
                    b3.Click += new RoutedEventHandler(aide_fonder_village);

                    if (u._mvt_restant == 0 || c.Ville != null || c.Ville_annexee != null)
                        b2.IsEnabled = false;

                    if (u._mvt_restant == 0)
                        b.IsEnabled = false;
                    else
                    {
                        unite_peut_bouger = true;
                        if (_unites_selectionnees.Contains(u))
                            b.IsChecked = true;
                    }
                    s.Children.Add(b);
                    s.Children.Add(l);
     
                    s.Children.Add(b2);
                    s.Children.Add(b3);

                    ongletUniteU.listeEnseignant.Children.Add(s);
                }
                //Sinon c'est un étudiant
                else
                {
                    StackPanel s = new StackPanel();
                    s.Orientation = Orientation.Horizontal;

                    Label l = new Label();
                    l.Width = 200;
                    l.Content = "Vie : " + u._vie_restante + " - Mouvement restant : " + u._mvt_restant;

                    CheckBox b = new CheckBox();
                    b.Tag = u;
                    b.VerticalAlignment = VerticalAlignment.Center;
                    if (u._mvt_restant == 0)
                        b.IsEnabled = false;
                    else
                    {
                        unite_peut_bouger = true;
                        if (_unites_selectionnees.Contains(u))
                            b.IsChecked = true;
                    }

                    s.Children.Add(b);
                    s.Children.Add(l);

                    ongletUniteU.listeEtudiant.Children.Add(s);
                }
            }
            if (c.Unites[0]._joueur == _partie.getJoueurActif())
                element.IsEnabled = unite_peut_bouger;

            //Si il n'y a aucun directeur
            if (ongletUniteU.listeDirecteur.Children.Count == 0){
                Label l = new Label();
                l.Content = "Aucun directeur";
                l.IsEnabled = false;
                ongletUniteU.listeDirecteur.Children.Add(l);
            }
            //Si il n'y a aucun enseignant
            if (ongletUniteU.listeEnseignant.Children.Count == 0)
            {
                Label l = new Label();
                l.Content = "Aucun enseignant";
                l.IsEnabled = false;
                ongletUniteU.listeEnseignant.Children.Add(l);
            }
            //Si il n'y a aucun étudiant
            if (ongletUniteU.listeEtudiant.Children.Count == 0)
            {
                Label l = new Label();
                l.Content = "Aucun étudiant";
                l.IsEnabled = false;
                ongletUniteU.listeEtudiant.Children.Add(l);
            }
        }

        /// <summary>
        /// Méthode appellée lorsque l'utilisateur souhaite une aide pour fonder un village
        /// </summary>
        /// <param name="sender">Bouton cliqué</param>
        /// <param name="e">Evènement</param>
        private void aide_fonder_village(object sender, RoutedEventArgs e)
        {
            Button b = sender as Button;

            Unite u = (Unite) b.Tag;

            //Affiche la fenêtre d'aide
            Window w = new Window_Aide(this,u.Case.meilleursCasesPourUnVillage());
            w.Show();
        }
      
        /// <summary>
        /// Méthode de mise à jour de l'onglet Ville
        /// </summary>
        /// <param name="c">Case selectionnée</param>
        private void updateOngletVille(Case c){

            //Si la case est une ville, on affiche les différentes informations
            if (c.Ville != null && c.Ville.Joueur == _partie.getJoueurActif())
            {
                ongletVilleU.Ville = c.Ville;
                tab_control.SelectedItem = ongletVille;
                foreach (UIElement u in ongletVilleU.gridVille.Children)
                    u.Visibility = Visibility.Visible;

                ongletVilleU.onglet_ville_fruit_stock.Content = c.Ville._nourriture;
                ongletVilleU.onglet_ville_minerais_stock.Content = c.Ville._minerai;

                ongletVilleU.onglet_ville_fruit.Content = c.Ville.productionFruit();
                ongletVilleU.onglet_ville_minerais.Content = c.Ville.productionMinerais();

                ongletVilleU.onglet_ville_population.Content = c.Ville._population;

                if(c.Ville.UniteAProduire.Equals("Etudiant"))
                    ((ComboBoxItem)ongletVilleU.combo.Items.GetItemAt(2)).IsSelected = true;
                else if (c.Ville.UniteAProduire.Equals("Enseignant"))
                    ((ComboBoxItem)ongletVilleU.combo.Items.GetItemAt(1)).IsSelected = true;
                else
                    ((ComboBoxItem)ongletVilleU.combo.Items.GetItemAt(0)).IsSelected = true;
                
                //Si le joueur possède déjà un directeur
                if (c.Ville.Joueur.possedeDirecteur())
                {
                    ongletVilleU.Directeur.IsEnabled = false;
                }
                else
                    ongletVilleU.Directeur.IsEnabled = true;

                ongletVilleU.ville_aucun.Visibility = Visibility.Hidden;

                //On active l'onglet
                ongletVille.IsEnabled = true;
            }
            //Sinon
            else
            {
                foreach (UIElement u in ongletVilleU.gridVille.Children)
                {
                    u.Visibility = Visibility.Hidden;
                }
                ongletVilleU.ville_aucun.Visibility = Visibility.Visible;

                //On désactive l'onglet
                ongletVille.IsEnabled = false;
            }
        }
    
        /// <summary>
        /// Méthode appelée lorsque l'utilisateur clique sur un bouton "Fonder un village"
        /// </summary>
        /// <param name="sender">Bouton appuyée</param>
        /// <param name="k">Evènement</param>
        private void fonder_village(object sender, RoutedEventArgs k)
        {
            Enseignant u  = (Enseignant)((sender as Button).Tag);
            Case c = u.Case;
            u.creerVillage();
            _partie.getJoueurActif().vueSur();
            updateOnglets(c);
        }
        
        /// <summary>
        /// Méthode appelée lorsque l'utilisateur presse une touche
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="k"></param>
        private void touche_appuyee(object sender, KeyEventArgs k){

            //Si le joueur veut finir le tour
            if (k.Key == Key.Enter)
            {
                finTour(null, null);
                return;
            }

            //Si le joueur veut sauvegarder la partie
            if (k.Key == Key.S && Keyboard.IsKeyDown(Key.LeftCtrl))
            {
                sauvegarder_partie(null,null);
                return;
            }

            //Si le joueur veut quitter la partie
            if (k.Key == Key.Q && Keyboard.IsKeyDown(Key.LeftCtrl))
            {
                quitter(null, null);
                return;
            }

            //Si il a appuyé sur une des flèches du clavier
            if (k.Key == Key.Down || k.Key == Key.Up || k.Key == Key.Right || k.Key == Key.Left)
            {
                int offset_x = 0;
                int offset_y = 0;

                //Tests de la touche appuyée
                if (k.Key == Key.Down)
                    offset_y = 1;
                else if (k.Key == Key.Up)
                    offset_y = -1;
                else if (k.Key == Key.Right)
                    offset_x = 1;
                else if (k.Key == Key.Left)
                    offset_x = -1;

                Hashtable listeDirecteur =  new Hashtable();
                int i = 0;
                foreach (UIElement ui in ongletUniteU.listeDirecteur.Children)
                {
                    listeDirecteur.Add(i, ui);
                    i++;
                }
                Hashtable listeEnseignant =  new Hashtable();
                i = 0;
                foreach (UIElement ui in ongletUniteU.listeEnseignant.Children)
                {
                    listeEnseignant.Add(i, ui);
                    i++;
                }
                Hashtable listeEtudiant = new Hashtable();
                i = 0;
                foreach (UIElement ui in ongletUniteU.listeEtudiant.Children)
                {
                    listeEtudiant.Add(i, ui);
                    i++;
                }

                bool reussi = true;
                Unite un = null;
                //On bouge tous les unités sélectionnées
                for (i = 0; i < listeDirecteur.Count; i++ )
                {
                    if (listeDirecteur[i].GetType() == typeof(StackPanel))
                        foreach (Object o2 in ((StackPanel)listeDirecteur[i]).Children)
                        {
                            if (o2.GetType() == typeof(CheckBox))
                            {
                                CheckBox c = o2 as CheckBox;
                                if (c.IsChecked == true)
                                {
                                    Unite u = (Unite)c.Tag;

                                    if (u.deplacer(_partie._carte.getCase(u.Case._x + offset_x, u.Case._y + offset_y)))
                                    {
                                        un = u;
                                        _unites_selectionnees.Add(u);
                                    }
                                    else
                                    {
                                        reussi = false;
                                    }
                                }

                            }
                        }
                }

                for (i = 0; i < listeEnseignant.Count; i++ )
                {
                    if (listeEnseignant[i].GetType() == typeof(StackPanel))
                        foreach (Object o2 in ((StackPanel)listeEnseignant[i]).Children)
                        {
                            if (o2.GetType() == typeof(CheckBox))
                            {
                                CheckBox c = o2 as CheckBox;
                                if (c.IsChecked == true)
                                {
                                    Unite u = (Unite)c.Tag;

                                    if (u.deplacer(_partie._carte.getCase(u.Case._x + offset_x, u.Case._y + offset_y)))
                                    {
                                        un = u;
                                        _unites_selectionnees.Add(u);
                                    }
                                    else
                                    {
                                        reussi = false;
                                    }
                                }

                            }
                        }
                }
                for(i = 0; i<listeEtudiant.Count;i++)
                {
                    if (listeEtudiant[i].GetType() == typeof(StackPanel))
                        foreach (Object o2 in ((StackPanel)listeEtudiant[i]).Children)
                        {
                            if (o2.GetType() == typeof(CheckBox))
                            {
                                CheckBox c = o2 as CheckBox;
                                if (c.IsChecked == true)
                                {
                                    Unite u = (Unite)c.Tag;

                                    if (u.deplacer(_partie._carte.getCase(u.Case._x + offset_x, u.Case._y + offset_y)))
                                    {
                                        un = u;
                                        _unites_selectionnees.Add(u);
                                    }
                                    else
                                    {
                                        reussi = false;
                                    }
                                }

                            }
                        }
                }

                if (un !=null && reussi && un.Case!=null)
                    clique_sur_une_case(((Tuple<Rectangle, Label>)_cases[un.Case]).Item1, null);
            }
                
        }

        /// <summary>
        /// Méthode appelée lorsque le joueur clique sur le bouton de "Fin de tour"
        /// </summary>
        /// <param name="sender">Bouton pressée</param>
        /// <param name="e">Evènement</param>
        private void finTour(object sender, RoutedEventArgs e)
        {
            //Joueur suivant
            _partie.joueurSuivant();
            _unites_selectionnees.Clear();

            //On centre la vue sur la dernière case qu'il avait sélectionnée
            Rectangle r = (Rectangle)_derniere_case_selectionne[_partie.getJoueurActif()];
            double offset_x = (Grid.GetColumn(r)) * 50 + ((this.ActualWidth - 200) / 2) - (this.ActualWidth - 200);
            double offset_y = (Grid.GetRow(r)) * 50 + ((this.ActualHeight - 200) / 2) - (this.ActualHeight - 200);
            scroll.ScrollToHorizontalOffset(offset_x);
            scroll.ScrollToVerticalOffset(offset_y);

            clique_sur_une_case(r,null);
        }

        /// <summary>
        /// Méthode appelée lorsque le joueur souhaite sauvegarder la partie
        /// Ouverture d'une boite de sauvegarde
        /// </summary>
        /// <param name="sender">Element</param>
        /// <param name="e">Evenement</param>
        private void sauvegarder_partie(object sender, RoutedEventArgs e)
        {

            Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
            dlg.FileName = "sauvegarde_partie"; 
            dlg.DefaultExt = ".civ"; 
            dlg.Filter = "Sauvegarde|*.civ";

            Nullable<bool> result = dlg.ShowDialog();

            if (result == true)
            {
                _partie.sauvegarder(dlg.FileName);
            }
        }


        /// <summary>
        /// Méthode appelée lorsque l'utilisateur souhaite quitter le jeu
        /// </summary>
        /// <param name="sender">Element</param>
        /// <param name="e">Evenement</param>
        private void quitter(object sender, RoutedEventArgs e)
        {
            Window w = new Window_Lancement();
            w.Show();
            this.Close();
        }

        /// <summary>
        /// Méthode appelée lorsque l'utilisateur souhaite visualiser la documentation
        /// </summary>
        /// <param name="sender">Element</param>
        /// <param name="e">Evenement</param>
        private void charger_documentation(object sender, RoutedEventArgs e)
        {
            try
            {
                System.IO.File.WriteAllBytes("documentation_utilisateur.pdf", Civilisation.Properties.Resources.documentation_utilisateur);
                System.Diagnostics.Process.Start("documentation_utilisateur.pdf");
            }
            catch
            {
                string messageBoxText = "Impossible de charger la documentation. Veuillez vérifier que vous avez bien installé un lecteur de PDF.";
                string caption = "Problème lors du chargement";
                MessageBoxButton button = MessageBoxButton.OK;
                MessageBoxImage icon = MessageBoxImage.Error;
                System.Windows.MessageBox.Show(messageBoxText, caption, button, icon);
            }
        }


        /// <summary>
        /// Permet de sélectionner toutes les unités
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tout_selectionner_unites(object sender, RoutedEventArgs e)
        {
            foreach (Object o in ongletUniteU.listeDirecteur.Children)
            {
                if (o.GetType() == typeof(StackPanel))
                    foreach (Object o2 in ((StackPanel)o).Children)
                    {
                        if (o2.GetType() == typeof(CheckBox))
                        {
                            CheckBox c = o2 as CheckBox;
                            if(c.IsEnabled)
                                c.IsChecked = true;
                        }
                    }
            }

            foreach (Object ol in ongletUniteU.listeEnseignant.Children)
            {
                if (ol.GetType() == typeof(StackPanel))
                    foreach (Object o2 in ((StackPanel)ol).Children)
                    {
                        if (o2.GetType() == typeof(CheckBox))
                        {
                            CheckBox c = o2 as CheckBox;
                            if (c.IsEnabled)
                                c.IsChecked = true;
                        }
                    }
            }
            foreach (Object o in ongletUniteU.listeEtudiant.Children)
            {
                if (o.GetType() == typeof(StackPanel))
                    foreach (Object o2 in ((StackPanel)o).Children)
                    {
                        if (o2.GetType() == typeof(CheckBox))
                        {
                            CheckBox c = o2 as CheckBox;
                            if (c.IsEnabled)
                                c.IsChecked = true;
                        }
                    }
            }
        }
    }
}
